package com.aforce3.trailertracer.scenes;

import java.util.ArrayList;
import java.util.List;

import javax.media.j3d.Transform3D;
import javax.vecmath.Color3f;
import javax.vecmath.Point3d;

import com.aforce3.trailertracer.Ray;
import com.aforce3.trailertracer.optimizations.BoundingBox;
import com.aforce3.trailertracer.optimizations.Intersection;
import com.aforce3.trailertracer.optimizations.OctTree;
import com.aforce3.trailertracer.optimizations.SceneBoundingBox;

public class SceneGroup extends Scene
{
	List<Scene> children = new ArrayList<Scene>();
	OctTree boundingBox;
	
	public SceneGroup(){
		
	}
	
	public SceneGroup(BoundingBox b){
		boundingBox = new OctTree(b);
	}
	
	public SceneGroup(Point3d ulb, Point3d lrf){
		boundingBox = new OctTree(ulb, lrf);
	}

	/** Gets the color of the intersection of the ray and the scene. Return null if there is no intersection **/
	public Color3f getColor(Ray ray)
	{
		return getColor(ray, null);
	}

	public Color3f getColor(Ray ray, Scene child)
	{
		Scene closest = null;
		float dist = -1;
		float d = -1;
		for(Scene c : children)
		{
			if(c == child)
			{
				continue;
			}

			d = c.getDistance(ray);
			if(d > 0 && (dist == -1 || d < dist))
			{
				dist = d;
				closest = c;
			}
		}
		if(closest == null) return null;
		return closest.getColor(ray, child);
	}

	public float getDistance(Ray ray)
	{
		// get distance should not be called on another group
		float dist = -1;
		float d = -1;
		for(Scene c : children)
		{
			d = c.getDistance(ray);
			if(d > 0 && (dist == -1 || d < dist))
			{
				dist = d;
			}
		}
		return dist;
	}

	public Scene getClosest(Ray ray, Scene child)
	{
		/*
		// get closest
		float dist = -1;
		float d = -1;
		Scene scene = null;
		for(Scene c : children)
		{
			if(c != child)
			{
				d = c.getDistance(ray);

				if(d > 0 && (dist == -1 || d < dist))
				{
					dist = d;
					scene = c;
				}
			}
		}
		// return scene.getClosest();

		//System.out.println(scene);
		return scene;
		*/
		
		Intersection intersection = boundingBox.getIntersection(ray, child, true);
		if(intersection == null) return null;
		
		Scene n = intersection.getScene();
		
		//System.out.println(n + " : " + child);
		return n;
		
	}

	public Scene getClosestObject(Ray ray, Scene child)
	{
		/*
		float dist = -1;
		float d = -1;
		Scene scene = null;
		for(Scene c : children)
		{
			if(c != child && !c.isLight())
			{
				d = c.getDistance(ray);

				if(d > 0 && (dist == -1 || d < dist))
				{
					dist = d;
					scene = c;
				}
			}
		}
		return scene;
		*/
		
		Intersection intersection = boundingBox.getIntersection(ray, child, false);
		if(intersection == null) return null;
		
		Scene n = intersection.getScene();
		
		//System.out.println(n + " : " + child);
		return n;
		
	}

	public void add(Scene child)
	{
		children.add(child);
		child.setParent(this);
		
		if (boundingBox == null){
			//boundingBox.addScene(child);
			System.out.println("bounding box is not set");
		}else{
			boundingBox.addScene(child);
		}
		
		System.out.println("added " + child);
	}

	public ArrayList<PointLight> getLights()
	{
		ArrayList<PointLight> lights = new ArrayList<PointLight>();
		for(Scene child : children)
		{
			lights.addAll(child.getLights());
		}
		return lights;
	}

	@Override
	protected void applyTransform(Transform3D t)
	{
		for(Scene child : children)
		{
			// applies self transform then the transform of the group
			child.applyTransform(t);
		}
	}

	@Override
	public void applyTransform()
	{
		for(Scene child : children)
		{
			// applies self transform then the transform of the group
			child.applyTransform();
			child.applyTransform(transformation);
		}
	}

	public BoundingBox getBoundingBox()
	{
		return boundingBox;
	}
}
